#pragma once
#include "../mqcommon/helper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <mutex>
#include <sstream>

namespace wzf
{
    struct Binding
    {
        using ptr = std::shared_ptr<Binding>;
        std::string exchange_name;
        std::string msgqueue_name;
        std::string binding_key;
        Binding(){}
        Binding(const std::string& exchange_name_, const std::string& msgqueue_name_, const std::string& bindking_key_)
            : exchange_name(exchange_name_), msgqueue_name(msgqueue_name_), binding_key(bindking_key_)
        {}
    };

    using MsgQueueBindingMap = std::unordered_map<std::string, Binding::ptr>;       //队列 ：绑定信息；所有队列对应的的绑定信息
    using ExchangeBindingMap = std::unordered_map<std::string, MsgQueueBindingMap>; //交换机 ：队列；  一个交换机对应多个队列

    // using ExchangeBindingMap = std::unordered_map<std::string, Binding::ptr>;  
    // using ExchangeBindingMap = std::unordered_map<std::string, Binding::ptr>;  
    //这样会多一步判断而且多一次遍历，智能指针要释放对象，引用计数要为0，比方说删了交换对应的binging，
    //然后在删队列对应的就要通过binding指针指向的exchange_name是不是要删除的交换机，简单来说需要释放的指针变多了
    
    class BindingMapper                        //绑定信息的持久化管理
    {
    public:
        BindingMapper(const std::string& dbfile)
            : _sql_helper(dbfile)
        {
            std::string path = FileHelper::getParentDirectory(dbfile); 
            FileHelper::createDirectory(path);          //创建父目录
            assert(_sql_helper.open());
            CreateTable();
        }
        void CreateTable()
        {
            std::string create_sql = "create table if not exists binding_table(\
                exchange_name varchar(32), \
                msgqueue_name varchar(32), \
                binding_key varchar(128));";
            assert(_sql_helper.exec(create_sql, nullptr, nullptr));
        }
        void RemoveTable()
        {
            std::string drop_sql = "drop table if exists binding_table";
            assert(_sql_helper.exec(drop_sql, nullptr, nullptr));
        }
        bool Insert(const Binding::ptr& ptr)
        {
            std::stringstream insert_sql;
            insert_sql << "insert into binding_table values(";
            insert_sql << "'" << ptr->exchange_name << "',"; 
            insert_sql << "'" << ptr->msgqueue_name << "',"; 
            insert_sql << "'" << ptr->binding_key << "');"; 
            // DLOG("生成的 SQL 语句: %s", ss.str().c_str());
            return _sql_helper.exec(insert_sql.str(), nullptr, nullptr);
        }
        bool Remove(const std::string& exchangename, const std::string& msgqueuename)
        {
            std::stringstream remove_sql;
            remove_sql << "delete from binding_table where ";
            remove_sql << "exchange_name='" << exchangename << "' and ";
            remove_sql << "msgqueue_name='" << msgqueuename << "';";
            return _sql_helper.exec(remove_sql.str(), nullptr, nullptr);
        }
        bool RemoveExchangeBindings(const std::string& exchangename)
        {
            std::stringstream remove_sql;
            remove_sql << "delete from binding_table where exchange_name="; 
            remove_sql << "'" << exchangename << "';";
            return _sql_helper.exec(remove_sql.str(), nullptr, nullptr);  //这里也不会false。 
        }
        bool RemoveMsgQueueBindings(const std::string& queuename)
        {
            std::stringstream remove_sql;
            remove_sql << "delete from binding_table where msgqueue_name=";
            remove_sql << "'" << queuename << "';";
            return _sql_helper.exec(remove_sql.str(), nullptr, nullptr);  //这里也不会false。
        }

        ExchangeBindingMap Recovery()
        {
            ExchangeBindingMap result;
            std::string select_sql = "select * from binding_table";
            _sql_helper.exec(select_sql, SelectCallBack, &result);
            return result;
        }
    private:
    static int SelectCallBack(void* arg, int col, char** row, char** fields)
    {
        ExchangeBindingMap* result = static_cast<ExchangeBindingMap*>(arg);
        auto ptr = std::make_shared<Binding>(row[0], row[1], row[2]);
        MsgQueueBindingMap& mbmp = (*result)[ptr->exchange_name];  //不存在自动创建 键，和值 
        mbmp.insert({ptr->msgqueue_name, ptr});
        return 0;
    }
    private:
        SqliteHelper _sql_helper;
    };
    
    class BindingManager
    {
    public:
        BindingManager(const std::string dbfile)
            :_mapper(dbfile)
        {
            _bindings = _mapper.Recovery();
        }
        bool Bind(const std::string& exchangename, const std::string& msgqueuename, const std::string& key, bool durable)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(exchangename);
            if(it != _bindings.end() && it->second.find(msgqueuename) != it->second.end()) return false;
            // if(_bindings.count(exchangename) || _bindings[exchangename].count(msgqueuename)) return false;

            MsgQueueBindingMap& mbmp = _bindings[exchangename];  //不存在自动创建 键，和值 
            auto ptr = std::make_shared<Binding>(exchangename, msgqueuename, key);
            mbmp.insert({msgqueuename, ptr});
            if(durable) _mapper.Insert(ptr);  //取决于交换机和队列是否都是持久化，但是这样会增加耦合，所以可以交给外部来做 
            return true;
        }
        
        void UnBind(const std::string& exchangename, const std::string& msgqueuename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            
            if(_bindings.count(exchangename) == false) return;
            if(_bindings[exchangename].count(msgqueuename) == false) return;
            _bindings[exchangename].erase(msgqueuename);
            _mapper.Remove(exchangename, msgqueuename);   //这里也要判断下是不是持久化的
        }
        void RemoveExchangeBindings(const std::string& exchangename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _bindings.erase(exchangename);
            _mapper.RemoveExchangeBindings(exchangename);
        }
        void RemoveMsgQueueBindings(const std::string& msgqueuename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveMsgQueueBindings(msgqueuename); 
            for(auto it = _bindings.begin(); it != _bindings.end(); it++)       //删除每一个交换机里的队列
            {
                it->second.erase(msgqueuename); 
            }
        }
        MsgQueueBindingMap GetExchangeBindings(const std::string& exchangename) //这个交换机对应的所有的 队列和绑定的映射
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_bindings.count(exchangename) == false)
                return MsgQueueBindingMap();
            return _bindings[exchangename];
        }
        Binding::ptr GetBinding(const std::string& exchangename, const std::string& msgqueuename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_bindings.count(exchangename) == false) 
                return nullptr;
            if(_bindings[exchangename].count(msgqueuename)  == false)
                return nullptr;
            return _bindings[exchangename][msgqueuename];
        }
        bool Exists(const std::string& exchangename, const std::string& msgqueuename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_bindings.count(exchangename) == false) 
                return false;
            if(_bindings[exchangename].count(msgqueuename)  == false)
                return false;
            return true;
        }
        size_t Size()
        {
            size_t total_size = 0;
            std::unique_lock<std::mutex> lock(_mutex);
            for(auto it = _bindings.begin(); it != _bindings.end(); it++)       //删除每一个交换机里的队列
            {
                total_size += it->second.size(); 
            }
            return total_size;
        }
        void Clear() 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveTable();
            _bindings.clear();
        }
    private:
        std::mutex _mutex;
        BindingMapper _mapper;
        ExchangeBindingMap _bindings;
    };
}

